package com.jzy.weblog.jwt.filter;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jzy.weblog.jwt.exception.UsernameOrPasswordNullException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
// 基于 Spring Security 的核心机制之一，专门用于处理用户登录请求，提取用户名和密码，并交给 Spring Security 来验证。
// AbstractAuthenticationProcessingFilter：是 Spring Security 中专门处理 身份认证请求 的过滤器。
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     *  指定用户登录的访问地址
     *  设置这个过滤器只在请求路径是 /login 且方法为 POST 时触发。
     */
    public JwtAuthenticationFilter() {
        // 当请求路径匹配 /login 并且请求方法为 POST 时，该过滤器将被触发。
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    // 实现用户身份验证的具体逻辑
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        ObjectMapper mapper = new ObjectMapper();
        // 解析提交的 JSON 数据
        JsonNode jsonNode = mapper.readTree(request.getInputStream());
        JsonNode usernameNode = jsonNode.get("username");
        JsonNode passwordNode =  jsonNode.get("password");

        // 判断用户名、密码是否为空
        if (Objects.isNull(usernameNode) || Objects.isNull(passwordNode)
                || StringUtils.isBlank(usernameNode.textValue()) || StringUtils.isBlank(passwordNode.textValue())) {
            throw new UsernameOrPasswordNullException("用户名或密码不能为空");
        }

        String username = usernameNode.textValue();
        String password = passwordNode.textValue();

        // 将用户名、密码封装到 Token 中
        // Spring Security 中用于登录认证的标准认证请求对象（实现了 Authentication 接口）
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                = new UsernamePasswordAuthenticationToken(username, password);
        // 触发 Spring Security 的身份验证管理器执行实际的身份验证过程，然后返回身份验证结果。
        // 它会去调用配置的 UserDetailsService.loadUserByUsername(...) 方法，进行用户身份比对。
        return getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
    }
}
